package top.cardone.mapper.impl;

import com.google.common.base.Charsets;
import com.google.gson.Gson;
import lombok.Setter;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.Resource;
import top.cardone.cache.Cache;
import top.cardone.context.ApplicationContextHolder;
import top.cardone.core.CodeException;
import top.cardone.mapper.BeanMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * @author yao hai tao
 * @date 2016/10/2
 */
public class BeanMapperImpl implements BeanMapper {
    @Setter
    private String cacheBeanName = "cardone.bean.cache";

    @Override
    public <T> T getObjectByFilePathCache(Class<T> cls, String filePath) {
        return ApplicationContextHolder
                .getBean(Cache.class, this.cacheBeanName)
                .get(BeanMapper.class.getName(), 1, filePath, () -> this.getObjectByFilePath(cls, filePath));
    }

    @Override
    public <T> T getObjectByFilePath(Class<T> cls, String filePath) {
        Resource resource = ApplicationContextHolder.getResource(filePath);

        if (!resource.exists()) {
            return null;
        }

        try (InputStream is = resource.getInputStream()) {
            String jsonString = IOUtils.toString(is, Charsets.UTF_8);

            return ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, cls);
        } catch (IOException e) {
            throw new CodeException("", e);
        }
    }

    @Override
    public <T> T getObject(Class<T> cls, String jsonString, Map<String, Object> map) {
        if (StringUtils.isBlank(jsonString) || !StringUtils.startsWithIgnoreCase(jsonString, "{")) {
            jsonString = "{}";
        } else {
            jsonString = StringUtils.trim(jsonString);
        }

        //输入参数为 map 时，优化获取 request 参数后，再合并
        if (MapUtils.isNotEmpty(map) && Map.class.equals(cls)) {
            Map<String, Object> jsonMap = ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, Map.class);

            if (MapUtils.isNotEmpty(jsonMap)) {
                map.putAll(jsonMap);
            }

            return (T) map;
        }

        if (java.lang.String.class.equals(cls) || java.lang.Object.class.equals(cls)) {
            return (T) jsonString;
        }

        return ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, cls);
    }

    @Override
    public <T> T getObject(Class<T> cls, Object data) {
        if (java.util.Map.class.equals(cls) && data instanceof Map) {
            return (T) data;
        }

        if (java.lang.Object.class.equals(cls)) {
            return (T) data;
        }

        String jsonString = ApplicationContextHolder.getBean(Gson.class).toJson(data);

        if (java.lang.String.class.equals(cls)) {
            return (T) jsonString;
        }

        return ApplicationContextHolder.getBean(Gson.class).fromJson(jsonString, cls);
    }

    @Override
    public <T> T getObject(Class<T> cls, Map<String, Object> map, Map<String, Object> mapperMap) {
        Map<String, Object> newMap = top.cardone.context.util.MapUtils.newHashMap(map, mapperMap);

        return this.getObject(cls, newMap);
    }
}
